//! 身份证验证工具

use chrono::{Datelike, NaiveDate};
use regex::Regex;
use std::collections::HashMap;

/// 身份证验证结果
#[derive(Debug, Clone, PartialEq)]
pub enum IdCardValidationResult {
    /// 验证通过
    Valid,
    /// 验证失败，包含错误信息
    Invalid(String),
}

impl IdCardValidationResult {
    /// 检查验证是否通过
    /// 
    /// # 示例
    /// 
    /// ```
    /// use rust_utils::id_card::IdCardValidationResult;
    /// 
    /// let valid = IdCardValidationResult::Valid;
    /// let invalid = IdCardValidationResult::Invalid("错误信息".to_string());
    /// 
    /// assert_eq!(valid.is_valid(), true);
    /// assert_eq!(invalid.is_valid(), false);
    /// ```
    pub fn is_valid(&self) -> bool {
        match self {
            IdCardValidationResult::Valid => true,
            IdCardValidationResult::Invalid(_) => false,
        }
    }

    /// 获取错误信息（如果验证失败）
    /// 
    /// # 示例
    /// 
    /// ```
    /// use rust_utils::id_card::IdCardValidationResult;
    /// 
    /// let valid = IdCardValidationResult::Valid;
    /// let invalid = IdCardValidationResult::Invalid("错误信息".to_string());
    /// 
    /// assert_eq!(valid.error_message(), None);
    /// assert_eq!(invalid.error_message(), Some(&"错误信息".to_string()));
    /// ```
    pub fn error_message(&self) -> Option<&String> {
        match self {
            IdCardValidationResult::Valid => None,
            IdCardValidationResult::Invalid(msg) => Some(msg),
        }
    }
}

/// 身份证信息
#[derive(Debug, Clone)]
pub struct IdCardInfo {
    /// 身份证号码
    pub id_card: String,
    /// 出生日期 (YYYY-MM-DD)
    pub birth_date: String,
    /// 性别 (0: 女, 1: 男)
    pub gender: u8,
    /// 地区码
    pub area_code: String,
    /// 地区名称
    pub area_name: String,
}

/// 身份证验证器
pub struct IdCardValidator;

impl IdCardValidator {
    /// 验证18位身份证号码
    /// 
    /// # 示例
    /// 
    /// ```
    /// use rust_utils::id_card::{IdCardValidator, IdCardValidationResult};
    /// 
    /// let validator = IdCardValidator;
    /// let result = validator.validate_18("11010519491231002X");
    /// assert!(result.is_valid());
    /// 
    /// let result = validator.validate_18("110105194912310021"); // 错误的校验码
    /// assert!(!result.is_valid());
    /// ```
    pub fn validate_18(&self, id_card: &str) -> IdCardValidationResult {
        // 基本格式验证
        let re = Regex::new(r"^\d{17}[\dXx]$").unwrap();
        if !re.is_match(id_card) {
            return IdCardValidationResult::Invalid("身份证号码格式不正确".to_string());
        }

        // 验证地区码
        let area_code = &id_card[0..6];
        if !self.is_valid_area_code(area_code) {
            return IdCardValidationResult::Invalid("地区码不正确".to_string());
        }

        // 验证出生日期
        let birth_date_str = &id_card[6..14];
        match self.validate_birth_date(birth_date_str) {
            IdCardValidationResult::Valid => (),
            IdCardValidationResult::Invalid(msg) => return IdCardValidationResult::Invalid(msg),
        }

        // 验证校验码
        match self.validate_check_digit(id_card) {
            IdCardValidationResult::Valid => (),
            IdCardValidationResult::Invalid(msg) => return IdCardValidationResult::Invalid(msg),
        }

        IdCardValidationResult::Valid
    }

    /// 验证15位身份证号码
    /// 
    /// # 示例
    /// 
    /// ```
    /// use rust_utils::id_card::{IdCardValidator, IdCardValidationResult};
    /// 
    /// let validator = IdCardValidator;
    /// let result = validator.validate_15("110105491231002");
    /// assert!(result.is_valid());
    /// ```
    pub fn validate_15(&self, id_card: &str) -> IdCardValidationResult {
        // 基本格式验证
        let re = Regex::new(r"^\d{15}$").unwrap();
        if !re.is_match(id_card) {
            return IdCardValidationResult::Invalid("身份证号码格式不正确".to_string());
        }

        // 验证地区码
        let area_code = &id_card[0..6];
        if !self.is_valid_area_code(area_code) {
            return IdCardValidationResult::Invalid("地区码不正确".to_string());
        }

        // 验证出生日期
        let birth_date_str = &id_card[6..12];
        let full_birth_date = format!("19{}", birth_date_str);
        match self.validate_birth_date(&full_birth_date) {
            IdCardValidationResult::Valid => (),
            IdCardValidationResult::Invalid(msg) => return IdCardValidationResult::Invalid(msg),
        }

        IdCardValidationResult::Valid
    }

    /// 验证身份证号码（自动识别15位或18位）
    /// 
    /// # 示例
    /// 
    /// ```
    /// use rust_utils::id_card::{IdCardValidator, IdCardValidationResult};
    /// 
    /// let validator = IdCardValidator;
    /// let result = validator.validate("11010519491231002X");
    /// assert!(result.is_valid());
    /// 
    /// let result = validator.validate("110105491231002");
    /// assert!(result.is_valid());
    /// ```
    pub fn validate(&self, id_card: &str) -> IdCardValidationResult {
        match id_card.len() {
            18 => self.validate_18(id_card),
            15 => self.validate_15(id_card),
            _ => IdCardValidationResult::Invalid("身份证号码长度不正确".to_string()),
        }
    }

    /// 解析身份证信息
    /// 
    /// # 示例
    /// 
    /// ```
    /// use rust_utils::id_card::IdCardValidator;
    /// 
    /// let validator = IdCardValidator;
    /// let result = validator.parse("11010519491231002X");
    /// assert!(result.is_ok());
    /// 
    /// let info = result.unwrap();
    /// assert_eq!(info.gender, 0); // 女性
    /// ```
    pub fn parse(&self, id_card: &str) -> Result<IdCardInfo, String> {
        // 首先验证身份证号码
        let validation_result = self.validate(id_card);
        if !validation_result.is_valid() {
            return Err(validation_result.error_message().unwrap().clone());
        }

        let area_code;
        let birth_date_str;
        let gender_code;

        if id_card.len() == 18 {
            area_code = id_card[0..6].to_string();
            birth_date_str = format!(
                "{}-{}-{}",
                &id_card[6..10],
                &id_card[10..12],
                &id_card[12..14]
            );
            gender_code = id_card[16..17].parse::<u8>().unwrap();
        } else {
            area_code = id_card[0..6].to_string();
            birth_date_str = format!(
                "19{}-{}-{}",
                &id_card[6..8],
                &id_card[8..10],
                &id_card[10..12]
            );
            gender_code = id_card[14..15].parse::<u8>().unwrap();
        }

        let gender = gender_code % 2; // 0表示女性，1表示男性
        let area_name = self.get_area_name(&area_code).unwrap_or("未知地区".to_string());

        Ok(IdCardInfo {
            id_card: id_card.to_string(),
            birth_date: birth_date_str,
            gender,
            area_code,
            area_name,
        })
    }

    /// 验证地区码
    fn is_valid_area_code(&self, area_code: &str) -> bool {
        self.get_area_name(area_code).is_some()
    }

    /// 获取地区名称
    fn get_area_name(&self, area_code: &str) -> Option<String> {
        let area_map = self.get_area_map();
        area_map.get(area_code).cloned()
    }

    /// 验证出生日期
    fn validate_birth_date(&self, birth_date_str: &str) -> IdCardValidationResult {
        // 检查日期格式是否正确
        let re = Regex::new(r"^\d{4}\d{2}\d{2}$|^\d{4}-\d{2}-\d{2}$").unwrap();
        if !re.is_match(birth_date_str) {
            return IdCardValidationResult::Invalid("出生日期格式不正确".to_string());
        }

        // 解析年月日
        let date_str = birth_date_str.replace("-", "");
        let year = match date_str[0..4].parse::<i32>() {
            Ok(y) => y,
            Err(_) => return IdCardValidationResult::Invalid("出生年份不正确".to_string()),
        };

        let month = match date_str[4..6].parse::<u32>() {
            Ok(m) if m >= 1 && m <= 12 => m,
            _ => return IdCardValidationResult::Invalid("出生月份不正确".to_string()),
        };

        let day = match date_str[6..8].parse::<u32>() {
            Ok(d) if d >= 1 && d <= 31 => d,
            _ => return IdCardValidationResult::Invalid("出生日期不正确".to_string()),
        };

        // 检查日期是否有效
        if let Some(date) = NaiveDate::from_ymd_opt(year, month, day) {
            // 检查出生日期是否合理（不能是未来日期，也不能太久远）
            let current_date = chrono::Local::now().date_naive();
            if date > current_date {
                return IdCardValidationResult::Invalid("出生日期不能是未来日期".to_string());
            }

            // 检查是否超过合理年龄（假设最大150岁）
            let max_age_date = current_date.with_year(current_date.year() - 150).unwrap();
            if date < max_age_date {
                return IdCardValidationResult::Invalid("出生日期超过合理年龄范围".to_string());
            }

            IdCardValidationResult::Valid
        } else {
            IdCardValidationResult::Invalid("出生日期不正确".to_string())
        }
    }

    /// 验证18位身份证的校验码
    fn validate_check_digit(&self, id_card: &str) -> IdCardValidationResult {
        let weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        let check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];

        let mut sum = 0;
        for (i, c) in id_card[..17].chars().enumerate() {
            let digit = c.to_digit(10).unwrap();
            sum += digit * weights[i];
        }

        let remainder = (sum % 11) as usize;
        let expected_check_code = check_codes[remainder];

        let actual_check_code = id_card.chars().last().unwrap().to_ascii_uppercase();

        if expected_check_code == actual_check_code {
            IdCardValidationResult::Valid
        } else {
            IdCardValidationResult::Invalid("校验码不正确".to_string())
        }
    }

    /// 获取地区码映射表
    fn get_area_map(&self) -> HashMap<&'static str, String> {
        let mut area_map = HashMap::new();
        
        // 华北地区
        area_map.insert("110000", "北京市".to_string());
        area_map.insert("110100", "北京市市辖区".to_string());
        area_map.insert("110101", "东城区".to_string());
        area_map.insert("110102", "西城区".to_string());
        area_map.insert("110105", "朝阳区".to_string());
        area_map.insert("110106", "丰台区".to_string());
        area_map.insert("110107", "石景山区".to_string());
        area_map.insert("110108", "海淀区".to_string());
        area_map.insert("110109", "门头沟区".to_string());
        area_map.insert("110111", "房山区".to_string());
        area_map.insert("110112", "通州区".to_string());
        area_map.insert("110113", "顺义区".to_string());
        area_map.insert("110114", "昌平区".to_string());
        area_map.insert("110115", "大兴区".to_string());
        area_map.insert("110116", "怀柔区".to_string());
        area_map.insert("110117", "平谷区".to_string());
        area_map.insert("110118", "密云区".to_string());
        area_map.insert("110119", "延庆区".to_string());
        
        area_map.insert("120000", "天津市".to_string());
        area_map.insert("130000", "河北省".to_string());
        area_map.insert("140000", "山西省".to_string());
        area_map.insert("150000", "内蒙古自治区".to_string());
        
        // 东北地区
        area_map.insert("210000", "辽宁省".to_string());
        area_map.insert("220000", "吉林省".to_string());
        area_map.insert("230000", "黑龙江省".to_string());
        
        // 华东地区
        area_map.insert("310000", "上海市".to_string());
        area_map.insert("320000", "江苏省".to_string());
        area_map.insert("330000", "浙江省".to_string());
        area_map.insert("340000", "安徽省".to_string());
        area_map.insert("350000", "福建省".to_string());
        area_map.insert("360000", "江西省".to_string());
        area_map.insert("370000", "山东省".to_string());
        
        // 中南地区
        area_map.insert("410000", "河南省".to_string());
        area_map.insert("420000", "湖北省".to_string());
        area_map.insert("430000", "湖南省".to_string());
        area_map.insert("440000", "广东省".to_string());
        area_map.insert("450000", "广西壮族自治区".to_string());
        area_map.insert("460000", "海南省".to_string());
        
        // 西南地区
        area_map.insert("500000", "重庆市".to_string());
        area_map.insert("510000", "四川省".to_string());
        area_map.insert("520000", "贵州省".to_string());
        area_map.insert("530000", "云南省".to_string());
        area_map.insert("540000", "西藏自治区".to_string());
        
        // 西北地区
        area_map.insert("610000", "陕西省".to_string());
        area_map.insert("620000", "甘肃省".to_string());
        area_map.insert("630000", "青海省".to_string());
        area_map.insert("640000", "宁夏回族自治区".to_string());
        area_map.insert("650000", "新疆维吾尔自治区".to_string());
        
        // 特别行政区和省份
        area_map.insert("710000", "台湾省".to_string());
        area_map.insert("810000", "香港特别行政区".to_string());
        area_map.insert("820000", "澳门特别行政区".to_string());
        
        area_map
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_id_card_validation_result() {
        let valid = IdCardValidationResult::Valid;
        let invalid = IdCardValidationResult::Invalid("错误信息".to_string());

        assert_eq!(valid.is_valid(), true);
        assert_eq!(invalid.is_valid(), false);
        assert_eq!(valid.error_message(), None);
        assert_eq!(invalid.error_message(), Some(&"错误信息".to_string()));
    }

    #[test]
    fn test_validate_18() {
        let validator = IdCardValidator;

        // 有效的18位身份证
        let result = validator.validate_18("11010519491231002X");
        assert!(result.is_valid());

        // 无效的校验码
        let result = validator.validate_18("110105194912310021");
        assert!(!result.is_valid());
        assert_eq!(result.error_message(), Some(&"校验码不正确".to_string()));

        // 无效的格式
        let result = validator.validate_18("11010519491231002");
        assert!(!result.is_valid());
        assert_eq!(result.error_message(), Some(&"身份证号码格式不正确".to_string()));
    }

    #[test]
    fn test_validate_15() {
        let validator = IdCardValidator;

        // 有效的15位身份证
        let result = validator.validate_15("110105491231002");
        assert!(result.is_valid());

        // 无效的格式
        let result = validator.validate_15("1101054912310021");
        assert!(!result.is_valid());
        assert_eq!(result.error_message(), Some(&"身份证号码格式不正确".to_string()));
    }

    #[test]
    fn test_validate() {
        let validator = IdCardValidator;

        // 有效的18位身份证
        let result = validator.validate("11010519491231002X");
        assert!(result.is_valid());

        // 有效的15位身份证
        let result = validator.validate("110105491231002");
        assert!(result.is_valid());

        // 无效的长度
        let result = validator.validate("11010549123100");
        assert!(!result.is_valid());
        assert_eq!(result.error_message(), Some(&"身份证号码长度不正确".to_string()));
    }

    #[test]
    fn test_parse() {
        let validator = IdCardValidator;

        // 解析18位身份证
        let result = validator.parse("11010519491231002X");
        assert!(result.is_ok());
        
        let info = result.unwrap();
        assert_eq!(info.id_card, "11010519491231002X");
        assert_eq!(info.birth_date, "1949-12-31");
        assert_eq!(info.gender, 0); // 女性
        assert_eq!(info.area_code, "110105");
        assert_eq!(info.area_name, "朝阳区");

        // 解析15位身份证
        let result = validator.parse("110105491231002");
        assert!(result.is_ok());
        
        let info = result.unwrap();
        assert_eq!(info.id_card, "110105491231002");
        assert_eq!(info.birth_date, "1949-12-31");
        assert_eq!(info.gender, 0); // 女性
        assert_eq!(info.area_code, "110105");
        assert_eq!(info.area_name, "朝阳区");
    }
}